/*
 * Skybox.cpp
 *
 *  Created on: 16/06/2013
 *      Author: david
 */

#include "Skybox.h"

Skybox::Skybox(std::string topImage, std::string bottomImage, std::string leftImage, std::string rightImage, std::string farImage, std::string nearImage, Shader* program) {

	this->program = program;

	modelviewUniformHandle = this->program->getUniformHandle("modelview_matrix");
	if (modelviewUniformHandle == -1)
		exit(1);

	scaleX = 10.0;
	scaleY = 10.0;
	scaleZ = 10.0;

	top = new TgaImage(topImage.c_str());
	far = new TgaImage(farImage.c_str());
	bottom = new TgaImage(bottomImage.c_str());
	near = new TgaImage(nearImage.c_str());
	left = new TgaImage(leftImage.c_str());
	right = new TgaImage(rightImage.c_str());

	setCube();

	texID = new unsigned int[6];

	glGenTextures(6,texID);

	glBindTexture(GL_TEXTURE_2D, texID[0]);
	configTexture();
	glTexImage2D(GL_TEXTURE_2D,0,top->dataType,top->imgWidth,top->imgHeight,0,top->format, GL_UNSIGNED_BYTE,top->imgData);
	glBindTexture(GL_TEXTURE_2D, texID[1]);
	glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
	configTexture();
	glTexImage2D(GL_TEXTURE_2D,0,far->dataType,far->imgWidth,far->imgHeight,0,far->format, GL_UNSIGNED_BYTE,far->imgData);
	glBindTexture(GL_TEXTURE_2D, texID[2]);
	glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
	configTexture();
	glTexImage2D(GL_TEXTURE_2D,0,bottom->dataType,bottom->imgWidth,bottom->imgHeight,0,bottom->format, GL_UNSIGNED_BYTE,bottom->imgData);
	glBindTexture(GL_TEXTURE_2D, texID[3]);
	glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
	configTexture();
	glTexImage2D(GL_TEXTURE_2D,0,near->dataType,near->imgWidth,near->imgHeight,0,near->format, GL_UNSIGNED_BYTE,near->imgData);
	glBindTexture(GL_TEXTURE_2D, texID[4]);
	glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
	configTexture();
	glTexImage2D(GL_TEXTURE_2D,0,left->dataType,left->imgWidth,left->imgHeight,0,left->format, GL_UNSIGNED_BYTE,left->imgData);
	glBindTexture(GL_TEXTURE_2D, texID[5]);
	glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
	configTexture();
	glTexImage2D(GL_TEXTURE_2D,0,right->dataType,right->imgWidth,right->imgHeight,0,right->format, GL_UNSIGNED_BYTE,right->imgData);

	setVBO();

}

Skybox::~Skybox() {
}

void Skybox::render() {

	glUseProgram(program->programHandle);

	for(int i=0; i<6; i++) {
		glBindVertexArray(vaoHandle[i]);

		glEnable(GL_TEXTURE_2D);
		glActiveTexture(GL_TEXTURE0);
		glBindTexture(GL_TEXTURE_2D, texID[i]);
		int textureUniformHandle = program->getUniformHandle("texMap");
		glUniform1i(textureUniformHandle, 0);
		glUniformMatrix4fv(modelviewUniformHandle, 1, false, matrix.m);

		glDrawElements(GL_QUADS, 4, GL_UNSIGNED_INT, 0);
	}

	glBindTexture(GL_TEXTURE_2D, 0);
	glDisable(GL_TEXTURE_2D);
	glBindVertexArray(0);

}


void Skybox::setVBO(){


	int vertLoc = glGetAttribLocation(program->programHandle, "a_vertex");
	int texLoc = glGetAttribLocation(program->programHandle, "a_tex_coord");

	unsigned int indices[] = {0, 1, 2, 3};


	unsigned int vbo[3];

	glGenVertexArrays(6, vaoHandle);
	check_gl_error();
	//TOP --------------------------------------------------------------
	glBindVertexArray(vaoHandle[0]);
	glGenBuffers(3, vbo);
	glBindBuffer(GL_ARRAY_BUFFER, vbo[0]);
	glBufferData(GL_ARRAY_BUFFER, sizeof (float)*12, topVert, GL_STATIC_DRAW);
	glEnableVertexAttribArray(vertLoc);
	glVertexAttribPointer(vertLoc, 3, GL_FLOAT, GL_FALSE, 0, 0);
	check_gl_error();

	glBindBuffer(GL_ARRAY_BUFFER, vbo[1]);
	glBufferData(GL_ARRAY_BUFFER, sizeof (float)*8, topTexCoord, GL_STATIC_DRAW);
	check_gl_error();

	glEnableVertexAttribArray(texLoc);
	check_gl_error();

	glVertexAttribPointer(texLoc, 2, GL_FLOAT, GL_FALSE, 0, 0);
	check_gl_error();

	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vbo[2]);
	glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof (unsigned int)*4, indices, GL_STATIC_DRAW);
	check_gl_error();

	//FAR --------------------------------------------------------------
	glBindVertexArray(vaoHandle[1]);
	glGenBuffers(3, vbo);
	glBindBuffer(GL_ARRAY_BUFFER, vbo[0]);
	glBufferData(GL_ARRAY_BUFFER, sizeof (float)*12, farVert, GL_STATIC_DRAW);
	glEnableVertexAttribArray(vertLoc);
	glVertexAttribPointer(vertLoc, 3, GL_FLOAT, GL_FALSE, 0, 0);

	glBindBuffer(GL_ARRAY_BUFFER, vbo[1]);
	glBufferData(GL_ARRAY_BUFFER, sizeof (float)*8, farTexCoord, GL_STATIC_DRAW);
	glEnableVertexAttribArray(texLoc);
	glVertexAttribPointer(texLoc, 2, GL_FLOAT, GL_FALSE, 0, 0);

	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vbo[2]);
	glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof (unsigned int)*4, indices, GL_STATIC_DRAW);

	//BOTTOM --------------------------------------------------------------
	glBindVertexArray(vaoHandle[2]);
	glGenBuffers(3, vbo);
	glBindBuffer(GL_ARRAY_BUFFER, vbo[0]);
	glBufferData(GL_ARRAY_BUFFER, sizeof (float)*12, bottomVert, GL_STATIC_DRAW);
	glEnableVertexAttribArray(vertLoc);
	glVertexAttribPointer(vertLoc, 3, GL_FLOAT, GL_FALSE, 0, 0);

	glBindBuffer(GL_ARRAY_BUFFER, vbo[1]);
	glBufferData(GL_ARRAY_BUFFER, sizeof (float)*8, bottomTexCoord, GL_STATIC_DRAW);
	glEnableVertexAttribArray(texLoc);
	glVertexAttribPointer(texLoc, 2, GL_FLOAT, GL_FALSE, 0, 0);

	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vbo[2]);
	glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof (unsigned int)*4, indices, GL_STATIC_DRAW);

	//NEAR --------------------------------------------------------------
	glBindVertexArray(vaoHandle[3]);
	glGenBuffers(3, vbo);
	glBindBuffer(GL_ARRAY_BUFFER, vbo[0]);
	glBufferData(GL_ARRAY_BUFFER, sizeof (float)*12, nearVert, GL_STATIC_DRAW);
	glEnableVertexAttribArray(vertLoc);
	glVertexAttribPointer(vertLoc, 3, GL_FLOAT, GL_FALSE, 0, 0);

	glBindBuffer(GL_ARRAY_BUFFER, vbo[1]);
	glBufferData(GL_ARRAY_BUFFER, sizeof (float)*8, nearTexCoord, GL_STATIC_DRAW);
	glEnableVertexAttribArray(texLoc);
	glVertexAttribPointer(texLoc, 2, GL_FLOAT, GL_FALSE, 0, 0);

	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vbo[2]);
	glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof (unsigned int)*4, indices, GL_STATIC_DRAW);

	//LEFT --------------------------------------------------------------
	glBindVertexArray(vaoHandle[4]);
	glGenBuffers(3, vbo);
	glBindBuffer(GL_ARRAY_BUFFER, vbo[0]);
	glBufferData(GL_ARRAY_BUFFER, sizeof (float)*12, leftVert, GL_STATIC_DRAW);
	glEnableVertexAttribArray(vertLoc);
	glVertexAttribPointer(vertLoc, 3, GL_FLOAT, GL_FALSE, 0, 0);

	glBindBuffer(GL_ARRAY_BUFFER, vbo[1]);
	glBufferData(GL_ARRAY_BUFFER, sizeof (float)*8, leftTexCoord, GL_STATIC_DRAW);
	glEnableVertexAttribArray(texLoc);
	glVertexAttribPointer(texLoc, 2, GL_FLOAT, GL_FALSE, 0, 0);

	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vbo[2]);
	glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof (unsigned int)*4, indices, GL_STATIC_DRAW);

	//RIGHT --------------------------------------------------------------
	glBindVertexArray(vaoHandle[5]);
	glGenBuffers(3, vbo);
	glBindBuffer(GL_ARRAY_BUFFER, vbo[0]);
	glBufferData(GL_ARRAY_BUFFER, sizeof (float)*12, rightVert, GL_STATIC_DRAW);
	glEnableVertexAttribArray(vertLoc);
	glVertexAttribPointer(vertLoc, 3, GL_FLOAT, GL_FALSE, 0, 0);

	glBindBuffer(GL_ARRAY_BUFFER, vbo[1]);
	glBufferData(GL_ARRAY_BUFFER, sizeof (float)*8, rightTexCoord, GL_STATIC_DRAW);
	glEnableVertexAttribArray(texLoc);
	glVertexAttribPointer(texLoc, 2, GL_FLOAT, GL_FALSE, 0, 0);

	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vbo[2]);
	glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof (unsigned int)*4, indices, GL_STATIC_DRAW);


	glBindVertexArray(0);
	glBindBuffer(GL_ARRAY_BUFFER, 0);

	check_gl_error();
}

void Skybox::setCube() {
	//TOP ---------------------------------
	float auxVert1[] = {
			-0.5,	0.5,	0.5,
			-0.5,	0.5,	-0.5,
			0.5,	0.5,	-0.5,
			0.5,	0.5,	0.5
	};
	topVert = new float[12];
	for(int i=0; i<12; i++)
		topVert[i] = auxVert1[i];

	float auxTexCoord1[] = {
			0, 0,
			0, 1,
			1, 1,
			1, 0
	};
	topTexCoord = new float[8];
	for(int i=0; i<8; i++)
		topTexCoord[i]=auxTexCoord1[i];

	//FAR ---------------------------------
	float auxVert2[] = {
			-0.5,	0.5,	-0.5,
			-0.5,	-0.5,	-0.5,
			0.5,	-0.5,	-0.5,
			0.5,	0.5,	-0.5
	};
	farVert = new float[12];
	for(int i=0; i<12; i++)
		farVert[i] = auxVert2[i];

	float auxTexCoord2[] = {
			0, 0,
			0, 1,
			1, 1,
			1, 0
	};
	farTexCoord = new float[8];
	for(int i=0; i<8; i++)
		farTexCoord[i]=auxTexCoord2[i];

	//BOTTOM ---------------------------------
	float auxVert3[] = {
			-0.5,	-0.5,	-0.5,
			-0.5,	-0.5,	0.5,
			0.5,	-0.5,	0.5,
			0.5,	-0.5,	-0.5
	};
	bottomVert = new float[12];
	for(int i=0; i<12; i++)
		bottomVert[i] = auxVert3[i];

	float auxTexCoord3[] = {
			0, 0,
			0, 1,
			1, 1,
			1, 0
	};
	bottomTexCoord = new float[8];
	for(int i=0; i<8; i++)
		bottomTexCoord[i]=auxTexCoord3[i];

	//NEAR ---------------------------------
	float auxVert4[] = {
			-0.5,	0.5,	0.5,
			0.5,	0.5,	0.5,
			0.5,	-0.5,	0.5,
			-0.5,	-0.5,	0.5
	};
	nearVert = new float[12];
	for(int i=0; i<12; i++)
		nearVert[i] = auxVert4[i];

	float auxTexCoord4[] = {
			1, 0,
			0, 0,
			0, 1,
			1, 1
	};
	nearTexCoord = new float[8];
	for(int i=0; i<8; i++)
		nearTexCoord[i]=auxTexCoord4[i];

	//LEFT ---------------------------------
	float auxVert5[] = {
			-0.5,	0.5,	0.5,
			-0.5,	-0.5,	0.5,
			-0.5,	-0.5,	-0.5,
			-0.5,	0.5,	-0.5
	};
	leftVert = new float[12];
	for(int i=0; i<12; i++)
		leftVert[i] = auxVert5[i];

	float auxTexCoord5[] = {
			0, 0,
			0, 1,
			1, 1,
			1, 0
	};
	leftTexCoord = new float[8];
	for(int i=0; i<8; i++)
		leftTexCoord[i]=auxTexCoord5[i];

	//RIGHT ---------------------------------
	float auxVert6[] = {
			0.5,	0.5,	-0.5,
			0.5,	-0.5,	-0.5,
			0.5,	-0.5,	0.5,
			0.5,	0.5,	0.5
	};
	rightVert = new float[12];
	for(int i=0; i<12; i++)
		rightVert[i] = auxVert6[i];

	float auxTexCoord6[] = {
			0, 0,
			0, 1,
			1, 1,
			1, 0
	};
	rightTexCoord = new float[8];
	for(int i=0; i<8; i++)
		rightTexCoord[i]=auxTexCoord6[i];
}

void Skybox::configTexture(){
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
	glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL);
}

